package com.kang.gateway.filter;

import com.alibaba.fastjson.JSON;
import com.kang.common.R;
import com.kang.gateway.properties.AuthProperties;
import com.kang.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * 身份认证过滤器
 * 负责校验请求的 JWT Token 和 Redis Token 验证，
 * 确保用户合法性。
 */
@Component
@Slf4j
public class AuthFilter implements GlobalFilter, Ordered {

	@Autowired
	private StringRedisTemplate redisTemplate;

	@Autowired
	private AuthProperties properties;

	@Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		ServerHttpRequest request = exchange.getRequest();
		ServerHttpResponse response = exchange.getResponse();

		try {
			// 1. 从配置文件中获取白名单列表
			List<String> whiteList = properties.getWhites();
			String path = request.getURI().getPath();

			// 2. 判断当前的请求路径是否在白名单中
			if (whiteList.contains(path)) {
				return chain.filter(exchange);
			}

			// 3. 获取并验证请求头中的 Authorization 信息
			String authorizationHeader = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);

			if (authorizationHeader == null || !authorizationHeader.startsWith("Bearer ")) {
				return buildErrorResponse(response, "缺少或无效的授权信息", HttpStatus.UNAUTHORIZED);
			}

			String jwtToken = authorizationHeader.substring(7); // 去掉 "Bearer " 前缀

			// 4. 解析 JWT Token
			Claims claims = JwtUtils.parseToken(jwtToken);
			String uuid = claims.get("token", String.class);

			if (uuid == null) {
				return buildErrorResponse(response, "Token 不包含有效的 UUID", HttpStatus.UNAUTHORIZED);
			}

			String redisKey = "login-token:" + uuid;

			// 5. 验证 Redis 中是否存在该 Token
			if (!Boolean.TRUE.equals(redisTemplate.hasKey(redisKey))) {
				return buildErrorResponse(response, "Token 验证失败或已过期", HttpStatus.UNAUTHORIZED);
			}

			// 6. 验证通过，继续后续过滤器链
			return chain.filter(exchange);
		} catch (Exception e) {
			log.error("身份认证失败", e);
			return buildErrorResponse(response, "身份认证失败: " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
		}
	}

	/**
	 * 构建错误响应
	 *
	 * @param response ServerHttpResponse 对象
	 * @param message  错误信息
	 * @param status   HTTP 状态码
	 * @return Mono<Void>
	 */
	private Mono<Void> buildErrorResponse(ServerHttpResponse response, String message, HttpStatus status) {
		response.setStatusCode(status);
		response.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);

		R result = R.error(status.value(), message);
		byte[] responseBytes = JSON.toJSONString(result).getBytes(StandardCharsets.UTF_8);
		DataBuffer dataBuffer = response.bufferFactory().wrap(responseBytes);

		return response.writeWith(Mono.just(dataBuffer));
	}

	@Override
	public int getOrder() {
		return -100; // 过滤器优先级
	}
}
